;; supercollider/score.scm - (c) rohan drape, 2004-2005

;; A score is a list of OSC bundles.  The timestamps are given in
;; seconds where zero is the start of the score.  An OSC file is a
;; binary file format understood by the SC3 synthesis server, and
;; consists of a sequence of length prefixed OSC bundles.

;; Write the score `data' to `file-name'.

(define (score-write-osc-file data file-name)
  (unlink* file-name)
  (call-with-output-file
      file-name
    (lambda (port)
      (for-each 
       (lambda (bundle)
	 (let* ((purified-bundle (osc-purify bundle))
		(bundle-data (osc-encode-bundle purified-bundle)))
	   (write-int32 (u8vector-length bundle-data) port)
	   (write-u8vector bundle-data port)))
       data))))

;; Read the OSC file `file-name' and return the score data.

(define (score-read-osc-file file-name)
  (call-with-input-file
      file-name
    (lambda (port)
      (let loop ((result '()))
	(if (eof-object? (peek-char port))
	    (reverse result)
	    (loop (cons (osc-decode-bundle 
			 (read-u8vector (read-int32 port) port))
			result)))))))

;; Play the score `score' at the `current-server' using a managed
;; thread.

#|
(define (score-play t score)
  (tschedule-routine t (yield)
    (let loop ((time (utc))
	       (data score)
	       (past 0))
      (if (not (null? data))
	  (let* ((bundle (car data))
		 (interval (car bundle)))
	    (server-send-bundle time (cdr bundle))
	    (loop (yield (- interval past)) (cdr data) interval))))))
|#

;; Generate the command to request 'scsynth' to render `osc-file' to
;; the `output-file'.

(defineK (score-render-command
	  (osc-file "/tmp/score.osc")
	  (output-file "/tmp/score.aif")
	  (input-file "_")
	  (sample-rate 44100)
	  (header-format "AIFF")
	  (sample-format "int16")
	  (options #f)
	  (completion-string "")
	  (duration #f)
	  (scsynth "scsynth")
	  (output-channels 2))
  (string-append scsynth " "
		 "-N "
		 osc-file " "
		 input-file " "
		 output-file " "
		 (number->string sample-rate) " "
		 header-format " "
		 sample-format " "
		 "-o " (number->string output-channels)))

;; Write `score' to the OSC file `osc-file' and then use the host
;; command processor to render audio to `output-file'.

(define (score-render score osc-file output-file . rest)
  (score-write-osc-file score osc-file)
  (system (apply score-render-command osc-file output-file rest)))

;; Request the host to render `osc-file' as audio to `output-file'.

(define (score-render-osc-file osc-file output-file . rest)
  (system (apply score-render-command osc-file output-file rest)))
